import {
  Component,
  OnInit,
  OnDestroy,
  Input,
  ComponentRef,
  ChangeDetectorRef,
  ViewContainerRef,
  Inject,
  EventEmitter,
} from '@angular/core';

// import { Tetrimino } from '../models/tetrimino';
import { MinoCmp, IMinoProps } from './mino.cmp';
import { Shape } from '../models/shape';
import { DIMENSION, Dimension, Coord } from '../models/dimension';

@Component({
  moduleId: module.id,
  selector: 'th-tetris-matrix',
  templateUrl: 'matrix.cmp.html',
  styleUrls: ['matrix.cmp.css'],
  directives: [MinoCmp]
})
export class MatrixCmp implements OnInit, OnDestroy {

  get cols() { return this.dim[0]; }
  get rows() { return this.dim[1]; }

  rearrange = new EventEmitter<"GAME_OVER" | "LINE_CLEARD">();

  matrix: IMinoProps[][];
  grid: { left: string, top: string, width: string, height: string }[];

  get minos() {
    return this.matrix
      .reduce((acc, l) => acc.concat(l.filter(c => !!c)), []);
  }

  constructor(
    @Inject(DIMENSION) private dim: Dimension,
    private changeDetector: ChangeDetectorRef
  ) { }

  ngOnInit() {

    //Init mino matrix
    this.matrix = Array(this.rows)
      .fill(null).map(l => Array(this.cols).fill(null));

    //Draw grid
    this.grid = Array(this.cols * this.rows).fill(null)
      .map((__, i) => ({ x: i % this.cols, y: i / this.cols | 0 }))
      .map(c => ({
        left: `${c.x * 100 / this.cols}%`,
        top: `${c.y * 100 / this.rows}%`,
        width: `${100 / this.cols}%`,
        height: `${100 / this.rows}%`
      }));

  }
  

  ngOnDestroy() {
    // this.matrix.forEach(line => line.forEach(m => m && m.destroy()));
  }

  //It won't modify the to be locked tetrimino whatsoever, 
  //it only copys minos from it and put them in the locking place
  lockTetrimino(outline: { coords: Coord[], color: string }) {
    outline.coords.forEach(coord =>
      this.matrix[coord[1]][coord[0]] = { color: outline.color, coord });

    this.changeDetector.detectChanges();
  }

  clearLines() {
    let cnt = 0;
    this.matrix = this.matrix
      .map(l => l.every(c => !!c) ? (cnt++ , l.map(c => null)) : l);
    return cnt;
  }

  tighten() {
    let m = this.matrix
      , bound = m.length - 1
      , solid = m.reduceRight((s, l) =>
        l.every(c => !c) ? s :
          [
            l.map(
              p => !p ? p :
                { color: p.color, coord: [p.coord[0], bound - s.length] }
            ),
            ...s
          ],
        []
      )
      ;
    this.matrix = Array(m.length - solid.length).fill(null)
      .map(l => Array(this.cols).fill(null)).concat(solid);
    this.changeDetector.detectChanges();
  }

}